﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Collections.Generic;
using HasuSLLib;

namespace HasuSLUI
{


    #region BindingEventArgs

    public class BindingEventArgs
    {
        public Metadata Metadata { get; set; }

        public Control Control { get; set; }

        public object Entity { get; set; }

        public bool DataBinded = false;
    }

    public class CreateControlEventArgs
    {
        public Metadata Metadata { get; set; }

        public Control Control { get; set; }

        public bool ControlCreated = false;
    }
    #endregion

    public delegate void BindingHandler(object sender, BindingEventArgs e);

    public delegate void CreateControlHandler(object sender, CreateControlEventArgs e);

    #region BaseControlFactory

    public abstract class BaseControlFactory : IControlFactory
    {
        #region Create control (To create control dynamicaly as per metadata)
        
        public abstract Control CreateControl(Metadata metadata);

        public abstract event CreateControlHandler OnControlCreate;
        public abstract event CreateControlHandler OnUnknownControl;

        public abstract TextBlock CreateLabel(Metadata metadata, double width);
        
        #endregion

        #region Data binding (to bind data with entity as per metadata)


        public abstract event BindingHandler OnBinding;
        public abstract event BindingHandler OnUnknownBinding;

        public abstract void SetBinding(Control control ,Metadata metadata, object entity);

        #endregion

        #region Create Column
        
        public abstract DataGridColumn CreateColumn(Metadata metadata);

        public abstract void SetBinding(DataGridColumn column, Metadata metadata);

        #endregion
    }

    #endregion

    #region ControlFactory

    /// <summary>
    /// ControlFactory create the controls as per entity's metadata
    /// </summary>
    public class ControlFactory : BaseControlFactory
    {
        public override  event  BindingHandler OnBinding;
        public override event BindingHandler OnUnknownBinding;

        public override event CreateControlHandler OnControlCreate;
        public override event CreateControlHandler OnUnknownControl;

        public ControlFactory()
        {
            OnControlCreate += new CreateControlHandler(ControlFactory_OnControlCreate);
            OnUnknownControl += new CreateControlHandler(ControlFactory_OnUnknownControl);
            OnBinding += new BindingHandler(ControlFactory_OnBinding);
            OnUnknownBinding += new BindingHandler(ControlFactory_OnUnknownBinding);
        }

        #region global event code

        void ControlFactory_OnUnknownControl(object sender, CreateControlEventArgs e)
        {
            ;
        }

        void ControlFactory_OnControlCreate(object sender, CreateControlEventArgs e)
        {
            ;
        }

        void ControlFactory_OnUnknownBinding(object sender, BindingEventArgs e)
        {
            ;
        }

        void ControlFactory_OnBinding(object sender, BindingEventArgs e)
        {
            ;
        }

        #endregion


        #region CreateControl

        /// <summary>
        /// Creates the control as per metadata.
        /// </summary>
        /// <param name="metadata">The metadata.</param>
        /// <returns></returns>
        public override Control CreateControl(Metadata metadata)
        {
            Control control = null;
            
            RegisterdControl registeredControl = null;

            if (metadata == null)
                return control;

            CreateControlEventArgs CreateControlArgs = new CreateControlEventArgs() {  Metadata = metadata , Control= control};

            OnControlCreate(this, CreateControlArgs);

            if (CreateControlArgs.ControlCreated)
            {
                return CreateControlArgs.Control;
            }


            Type registeredType = null;

            if (UIDefaults.IsRegisterdControl(metadata.MetaType))
            {
                registeredType = metadata.MetaType;
            }
            else if (UIDefaults.IsRegisterdControl(metadata.MetaType.BaseType))
            {
                registeredType = metadata.MetaType.BaseType;
            }

            if (registeredType!=null )
            {
                registeredControl= UIDefaults.RegisterdControls[registeredType];
                control = (Control)Activator.CreateInstance(registeredControl.ControlType);

                if (registeredControl.OnCreateControl != null)
                {
                    registeredControl.OnCreateControl(control);
                }
            }
            else
            {
                if (metadata.MetaType.IsClass && Activator.CreateInstance(metadata.MetaType) is System.Collections.IEnumerable)
                {
                    if (metadata.MetaType.IsGenericType)
                    {
                        if (metadata.MetaType.GetGenericArguments().Length == 1 && UIDefaults.IsRegisterdControl(metadata.MetaType.GetGenericArguments()[0]))
                        {
                            registeredControl = UIDefaults.RegisterdControls[typeof(System.Collections.IEnumerable)];
                        }
                        else
                        {
                            registeredControl = UIDefaults.RegisterdControls[typeof(System.Collections.ICollection)];
                        }
                    }
                    else if (Activator.CreateInstance(metadata.MetaType) is System.Collections.ICollection)
                    {
                        registeredControl = UIDefaults.RegisterdControls[typeof(System.Collections.ICollection)]; 
                    }
                    else
                    {
                        registeredControl = UIDefaults.RegisterdControls[typeof(System.Collections.IEnumerable)];
                    }

                    if (registeredControl != null)
                    {
                        control = (Control)Activator.CreateInstance(registeredControl.ControlType);
                    }

                }
            }

            if (control == null)
            {
                OnUnknownControl(this, CreateControlArgs);
                control= CreateControlArgs.Control; 
            }
            
            if (control != null)
            {
                control.IsEnabled = metadata.Enable;
                
                if (registeredControl.DefaultWidth > 0)
                {
                    control.Width = registeredControl.DefaultWidth;
                }

                if (registeredControl.DefaultHeight > 0)
                {
                    control.Height = registeredControl.DefaultHeight;
                }
            }

            return control;
        }

        #endregion

        #region Data Binding

        /// <summary>
        /// Sets the data binding with entity.
        /// </summary>
        /// <param name="control">The control.</param>
        /// <param name="metadata">The metadata.</param>
        /// <param name="entity">The entity.</param>
        public override void SetBinding(Control control, Metadata metadata, object entity)
        {
            BindingEventArgs bindingArgs = new BindingEventArgs() 
            { 
                Entity = entity,
                Metadata = metadata,
                Control= control 
            };

            OnBinding(this, bindingArgs);
            
            if (bindingArgs.DataBinded)
                return;

            MetaBinding bind = new MetaBinding(metadata.Name);

            bind.Converter = metadata;

            if (metadata.ReadOnly)
            {
                bind.Mode = BindingMode.OneWay;
            }
            else
            {
                bind.Mode = BindingMode.TwoWay;
            }

            bind.NotifyOnValidationError = metadata.NotifyOnValidationError;
            bind.ValidatesOnExceptions = metadata.NotifyOnValidationError;
            bind.UpdateSourceTrigger = UpdateSourceTrigger.Default;
            
            bind.Source = entity;

            //DependencyProperty.RegisterAttached(
           //http://stackoverflow.com/questions/834929/silverlight-how-to-receive-notification-of-a-change-in-an-inherited-dependencypr

            Type registeredType = null;

            if (UIDefaults.IsRegisterdControl(metadata.MetaType))
            {
                registeredType = metadata.MetaType;
            }
            else if (UIDefaults.IsRegisterdControl(metadata.MetaType.BaseType))
            {
                registeredType = metadata.MetaType.BaseType;
            }
            else
            {
                if (metadata.MetaType.IsClass && Activator.CreateInstance(metadata.MetaType) is System.Collections.IEnumerable)
                {
                    if (metadata.MetaType.IsGenericType)
                    {
                        if (metadata.MetaType.GetGenericArguments().Length == 1 && UIDefaults.IsRegisterdControl(metadata.MetaType.GetGenericArguments()[0]))
                        {
                            registeredType = typeof(System.Collections.IEnumerable);
                        }
                        else
                        {
                            registeredType = typeof(System.Collections.ICollection);
                        }
                    }
                    else if (Activator.CreateInstance(metadata.MetaType) is System.Collections.ICollection)
                    {
                        registeredType = typeof(System.Collections.ICollection);
                    }
                    else
                    {
                        registeredType = typeof(System.Collections.IEnumerable);
                    }
                }
            }

            if (registeredType != null)
            {
                RegisterdControl registeredControl = UIDefaults.RegisterdControls[registeredType];

                try
                {
                    control.SetBinding(registeredControl.BindingProperty, bind);
                }
                catch (Exception ex)
                { 
                    System.Diagnostics.Debug.WriteLine("Exception :" + ex.Message) ;
                }

                if (registeredControl.OnDataBinding != null)
                {
                    registeredControl.OnDataBinding(control, metadata.GetValue(entity));
                }

            }

        }

        #endregion

        #region Create Label for control

        /// <summary>
        /// Creates the label as per metadata.
        /// </summary>
        /// <param name="metadata">The metadata.</param>
        /// <param name="width">The width.</param>
        /// <returns></returns>
        public override TextBlock CreateLabel(Metadata metadata, double width)
        {
            TextBlock tmpTxtblock = UIDefaults.CreateLabelControl();
            
            tmpTxtblock.Text = metadata.Title;
            tmpTxtblock.Width = width;

            return tmpTxtblock;
        }

        #endregion

        #region Grid Defaults code

        #region Create data Column

        public override DataGridColumn CreateColumn(Metadata metadata)
        {
            DataGridColumn column = null;
            
            RegisterdColumn regColumn =null;

            if (UIDefaults.IsRegisterdColumn(metadata.MetaType))
            {
                regColumn = UIDefaults.RegisterdColumns[metadata.MetaType];
                column = Activator.CreateInstance(regColumn.ColumnType) as DataGridColumn;
            }
            if (column == null)
            {
                column = new DataGridTextColumn();
            }
            if (column != null)
            {
                column.IsReadOnly = column.IsReadOnly ? true : metadata.ReadOnly;
                column.Header = metadata.Title;
                
                if (regColumn != null && regColumn.DefaultWidth > 0) 
                { column.Width = new DataGridLength( regColumn.DefaultWidth); }
            }
            return column;
        }

        #endregion

        #region Set data Binding for column

        public override void SetBinding(DataGridColumn column, Metadata metadata)
        {
            if (column is DataGridBoundColumn)
            {
                (column as DataGridBoundColumn).Binding = new Binding(metadata.Name);
            }
            
            RegisterdColumn regColumn =null;

            if (UIDefaults.IsRegisterdColumn(metadata.MetaType))
            {
                regColumn = UIDefaults.RegisterdColumns[metadata.MetaType];
                if (regColumn != null && regColumn.OnDataBinding != null)
                {
                    regColumn.OnDataBinding(column);
                }
            }
        }
        #endregion

        #endregion
    }   

    #endregion
}
